package pho.helper;

import java.util.HashMap;
import java.util.Map;

import pho.prowon.ImageData;

import com.drew.metadata.Tag;
import com.drew.metadata.iptc.IptcDirectory;

/**
 * @author Peter
 *
 * This is a collecion of methods that map from Drew Noakes Iptc Library 
 * to the JpegWriter/IptcWriter and the ImageData implementations.
 * It renames the Iptc tags to fulfill naming criterias for XML and
 * supports a reverse mapping from XML tagname to Hex code for writing back
 * to JPEG files
 * It also does the reverse type conversion 
 */
public class IptcTagNameConverter
{

	protected static final Map idTagNameMap = new HashMap();
	protected static final Map idReverseTagNameMap = new HashMap();

	/**
	 * a private constructor will prevent anybody from instantiating this class
	 * as it only has static methods
	 */
	private IptcTagNameConverter ()
	{
	}

	static
	{
		idTagNameMap.put(new Integer(IptcDirectory.TAG_RECORD_VERSION), "DirectoryVersion");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_CAPTION), "CaptionAbstract");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_WRITER), "WriterEditor");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_HEADLINE), "Headline");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_SPECIAL_INSTRUCTIONS), "SpecialInstructions");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_BY_LINE), "Byline");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_BY_LINE_TITLE), "BylineTitle");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_CREDIT), "Credit");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_SOURCE), "Source");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_OBJECT_NAME), "ObjectName");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_DATE_CREATED), "DateCreated");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_CITY), "City");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_PROVINCE_OR_STATE), "ProvinceState");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_COUNTRY_OR_PRIMARY_LOCATION), "CountryPrimaryLocation");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_ORIGINAL_TRANSMISSION_REFERENCE), "OriginalTransmissionReference");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_CATEGORY), "Category");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_SUPPLEMENTAL_CATEGORIES), "SupplementalCategorys");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_URGENCY), "Urgency");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_KEYWORDS), "Keywords");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_COPYRIGHT_NOTICE), "CopyrightNotice");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_RELEASE_DATE), "ReleaseDate");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_RELEASE_TIME), "ReleaseTime");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_TIME_CREATED), "TimeCreated");
		idTagNameMap.put(new Integer(IptcDirectory.TAG_ORIGINATING_PROGRAM), "OriginatingProgram");


		idReverseTagNameMap.put("DirectoryVersion", new Integer(IptcDirectory.TAG_RECORD_VERSION));
		idReverseTagNameMap.put("CaptionAbstract", new Integer(IptcDirectory.TAG_CAPTION));
		idReverseTagNameMap.put("WriterEditor", new Integer(IptcDirectory.TAG_WRITER));
		idReverseTagNameMap.put("Headline", new Integer(IptcDirectory.TAG_HEADLINE));
		idReverseTagNameMap.put("SpecialInstructions", new Integer(IptcDirectory.TAG_SPECIAL_INSTRUCTIONS));
		idReverseTagNameMap.put("Byline", new Integer(IptcDirectory.TAG_BY_LINE));
		idReverseTagNameMap.put("BylineTitle", new Integer(IptcDirectory.TAG_BY_LINE_TITLE));
		idReverseTagNameMap.put("Credit", new Integer(IptcDirectory.TAG_CREDIT));
		idReverseTagNameMap.put("Source", new Integer(IptcDirectory.TAG_SOURCE));
		idReverseTagNameMap.put("ObjectName", new Integer(IptcDirectory.TAG_OBJECT_NAME));
		idReverseTagNameMap.put("DateCreated", new Integer(IptcDirectory.TAG_DATE_CREATED));
		idReverseTagNameMap.put("City", new Integer(IptcDirectory.TAG_CITY));
		idReverseTagNameMap.put("ProvinceState", new Integer(IptcDirectory.TAG_PROVINCE_OR_STATE));
		idReverseTagNameMap.put("CountryPrimaryLocation", new Integer(IptcDirectory.TAG_COUNTRY_OR_PRIMARY_LOCATION));
		idReverseTagNameMap.put("OriginalTransmissionReference", new Integer(IptcDirectory.TAG_ORIGINAL_TRANSMISSION_REFERENCE));
		idReverseTagNameMap.put("Category", new Integer(IptcDirectory.TAG_CATEGORY));
		idReverseTagNameMap.put("SupplementalCategorys", new Integer(IptcDirectory.TAG_SUPPLEMENTAL_CATEGORIES));
		idReverseTagNameMap.put("Urgency", new Integer(IptcDirectory.TAG_URGENCY));
		idReverseTagNameMap.put("Keywords", new Integer(IptcDirectory.TAG_KEYWORDS));
		idReverseTagNameMap.put("CopyrightNotice", new Integer(IptcDirectory.TAG_COPYRIGHT_NOTICE));
		idReverseTagNameMap.put("ReleaseDate", new Integer(IptcDirectory.TAG_RELEASE_DATE));
		idReverseTagNameMap.put("ReleaseTime", new Integer(IptcDirectory.TAG_RELEASE_TIME));
		idReverseTagNameMap.put("TimeCreated", new Integer(IptcDirectory.TAG_TIME_CREATED));
		idReverseTagNameMap.put("OriginatingProgram", new Integer(IptcDirectory.TAG_ORIGINATING_PROGRAM));
	}
	
	/**
	 * Returns the ImageData name of a specified Tag as a String.
	 * @param tag the tag coming from a Directory
	 * @return the tag's name as a String in ImageData
	 */
	public static String getImageDataTagName(Tag tag)
	{
		Integer key = new Integer(tag.getTagType());
		return getImageDataTagName(key);
	}

	/**
	 * Returns the ImageData name of a specified Iptc key as a String.
	 * @param key the Iptc key 
	 * @return the key's name as a String in ImageData
	 */
	public static String getImageDataTagName(Integer key)
	{
		if (!idTagNameMap.containsKey(key))
		{
			String hex = Integer.toHexString(key.intValue());
			while (hex.length() < 4)
			{
				hex = "0" + hex;
			}
			System.out.println ("Unknown tag (0x" + hex + ")");
			return "";
		}
		return (String) idTagNameMap.get(key);
	}

	/**
	 * find out whether the passed tag name is in the list of 
	 * supported Tag names --> which means we could translate it into
	 * a hex code suitable for a Jpeg file
	 * @param tag the ImageData tag name
	 * @return true if this is a known tag name
	 */
	public static Boolean isKnownImageDataTagName(String tag)
	{
		return Boolean.valueOf(idReverseTagNameMap.containsKey(tag));
	}

	/**
	 * find out whether the passed tag's identifier is in the list of 
	 * supported Tag identifieres --> which means we could translate it from
	 * a hex code coming out of a Jpeg file
	 * @param tag the Iptc Tag 
	 * @return true if this is a known tag identifier
	 */
	public static Boolean isKnownTag(Tag tag)
	{
		Integer key = new Integer(tag.getTagType());
		return isKnownTag(key);
	}

	/**
	 * find out whether the passed hex code is in the list of 
	 * supported Tag identifieres --> which means we could translate it from
	 * a hex code coming out of a Jpeg file
	 * @param tag the hex code 
	 * @return true if this is a known tag identifier
	 */
	public static Boolean isKnownTag(Integer key)
	{
		return Boolean.valueOf(idTagNameMap.containsKey(key));
	}

	/**
	 * Returns the hex value id used in IptcDirectory for the passed
	 * ImageData tag name
	 * @param id the ImageData name
	 * @return the tag's hex value
	 */
	public static Integer getTagTypeFromid(String id)
	{
		if (!idReverseTagNameMap.containsKey(id))
		{
			return new Integer(0);
		}
		return (Integer) idReverseTagNameMap.get(id);
	}

	/**
	 * This method converts from Java objects to relevant IPTC octets for writing back IPTC data to a file.
	 * In case the value cannot be converted (e.g. date/time in invalid format) an empty byte array is returned
	 * @param tagIdentifier the IPTC tag id that needs conversion. 
	 * @param tagValue the string representation of the value which will be converted
	 * @return a byte array containing the binary representation of the IPTC tag for the file
	 */
	public static byte[] processTag(int tagIdentifier, String tagValue)
	{
		byte[] output;

		switch (tagIdentifier)
		{
			case IptcDirectory.TAG_RECORD_VERSION :
				// short			
				output = new byte[2];
				output[0] =
					(byte) ((Integer.decode(tagValue).intValue() & 0xFF00)
						>> 8);
				output[1] = (byte) (Integer.decode(tagValue).intValue() & 0xFF);
				return output;
			case IptcDirectory.TAG_URGENCY :
				// byte
				output = new byte[1];
				output[0] =
					(byte) ((Integer.decode(tagValue).intValue() & 0xFF));
				return output;

			case IptcDirectory.TAG_RELEASE_DATE :
			case IptcDirectory.TAG_DATE_CREATED :			
				// Date object
				return DateConverter.convertDateFormatToByteArray(tagValue, ImageData.getDateFormat(),"yyyyMMdd");		
			
			case IptcDirectory.TAG_RELEASE_TIME :
			case IptcDirectory.TAG_TIME_CREATED :
				// time...
				return DateConverter.convertDateFormatToByteArray(tagValue, ImageData.getTimeFormat(),"HHmmss");		
			default :
				// fall through
		}
		// If no special handling by now, treat it as a string
		return ((String) tagValue).getBytes();
	}
	
}
